package com.yc.thread.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 10个线程循环争夺一把锁
 * 总结：
 * 生产者/消费者问题 不能用读写锁（共享/独占锁）解决。因为无论是生产者，还是消费者都是"写"
 * 自己wait下来后，被唤醒后并不能马上动起来，还需要经过抢锁 并抢到之后才能动
 * 抢到锁之后，动是从wait的下一句开始动的，并不是从循环语句的第一句开始动的
 *  这个现象会看起来比较奇怪：抢锁的过程似乎变得透明了：我们一般认为执行synchronize(obj)或者执行lock.lock()才是抢锁
 *  但其实并不是。对wait之后的线程，抢锁就是"后台自动完成"，抢完锁，直接从wait下一句继续执行，而不是"从头开始"
 */
public class ReentrantLockTest3 {

    final static Object LOCK = new Object();

    public static void main(String[] args) throws InterruptedException {

        for(int i=1;i<3;i++){
            new Thread(new ThreadDemo(i)).start();
        }

    }

}

class ThreadDemo implements Runnable {
    Integer id;

    public ThreadDemo(Integer id) {
        this.id = id;
    }

    @Override

    //
    public void run() {

        for(int i=0;i<3;i++){


            synchronized (ReentrantLockTest3.LOCK) {
                System.out.println("线程: "+id+" 获得锁");

                ReentrantLockTest3.LOCK.notifyAll();
                System.out.println("线程: "+id+" notifyAll");
                try {
                    ReentrantLockTest3.LOCK.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
//                Thread.yield();//这样也不行：他短暂放弃之后立马又抢到手


                System.out.println("线程: "+id+" 放弃锁");
                //抢锁读开始是自己被唤醒，并且当锁被人释放读那一刻。和自己的代码走到哪一步没有关系
                //这个被自己wait到线程，下次醒来就是从wait下面这句话开始执行的，而不是for循环的第一句
                //一般情况下，wait自己肯定是出于什么原因，会有跟判断，此时的判断一定不要用if，而是要用while
                //因为当前线程被唤醒时，是唯一一个拿到锁的人？好像是啊，但它可能并不是被生产者唤醒的然后自己获得锁的
                //有可能是因为自己努力了好几轮之后，从同行手中抢到了锁，那么此时有可能已经不能处理了（抢了个寂寞）
                //那也就意味着，自己抢到锁了，也要判断一下是否能正常的往下执行。如果不能，那么抢到锁后，就得回到原地停下来
                if (Thread.holdsLock(ReentrantLockTest3.LOCK)) {
                    System.out.println("线程："+id+"---有线程获得锁---");
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("线程: "+id+" after wait...");
            }

        }
    }
}